package service

import (
	"context"
	"fmt"

	pb "bilinadmin/api/pb/server"

	"bilinadmin/internal/model"
	"bilinadmin/internal/object"

	"bilinadmin/internal/dao"

	"bilinadmin/pkg/lueerror"
)

// 角色权限服务
type rolePerService struct {
	*Service
	perms *object.Permissions
	name  string
}

var pSrv *rolePerService

// InitRolePermissionService 初始化角色权限逻辑层
func InitRolePermissionService() {
	pSrv = &rolePerService{
		Service: service,
		name:    "permission_service",
		perms:   nil,
	}
}

// GetRolePermissionSrv 获取角色权限逻辑层
func GetRolePermissionSrv() *rolePerService {
	return pSrv
}

func (srv *rolePerService) loadPermsMap() *object.Permissions {
	if srv.perms != nil {
		return srv.perms
	}
	perms, err := dao.GetPermissionDao().GetPermission(context.TODO())
	if err != nil {
		srv.logger.Bg().Info(fmt.Sprintf("failed to load permissions %s", err.Error()))
		return nil
	}
	srv.perms = object.NewPermissions(perms)
	return srv.perms
}

func (srv *rolePerService) getPermIdByRouter(refType int8, router string) int64 {
	return srv.loadPermsMap().GetPermissionIdByRouter(refType, router)
}

func (srv *rolePerService) getPermissionById(id int64) *model.Permission {
	return srv.loadPermsMap().GetPermissionById(id)
}

func (srv *rolePerService) getEmpRoleByName(ctx context.Context, refId int64, refType int8, name string) (*model.EmpRole, lueerror.LueError) {
	role, err := dao.GetRoleDao().GetEmpRoleByName(ctx, refId, refType, name)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return role, nil
}

// 管理员账号
func (srv *rolePerService) addAdminRole(ctx context.Context, brandId, refId int64, refType int8) (*model.EmpRole, lueerror.LueError) {
	var err error
	role, errL := srv.getEmpRoleByName(ctx, refId, refType, "管理员")
	if errL != nil {
		return nil, errL
	}
	if role != nil {
		return role, nil
	}
	role = model.NewEmpRole(brandId, refId, refType, "管理员", 0)
	// 设置权限
	role.SetAdmin()
	role.Id, err = dao.GetRoleDao().CreateEmpRole(ctx, role)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return role, nil
}

// 新增角色权限
func (srv *rolePerService) addOrUpdateRolePermissions(ctx context.Context, roleId, creator int64, refType int8, routers ...string) lueerror.LueError {
	if len(routers) == 0 {
		return nil
	}
	var perms []*model.RolePermission
	for _, r := range routers {
		p := model.NewRolePermission(roleId, creator)
		perId := srv.getPermIdByRouter(refType, r)
		if perId == 0 {
			return lueerror.InvalidPermission(fmt.Errorf("权限:%s加载异常", r))
		}
		p.AddPermission(perId)
		perms = append(perms, p)
	}
	err := dao.GetRoleDao().CreateOrUpdateRolePermissions(ctx, perms...)
	if err != nil {
		return lueerror.DbErr(err)
	}
	return nil
}

// 客户经理角色
func (srv *rolePerService) addMemberManager(ctx context.Context, brandId, refId int64, refType int8) (*model.EmpRole, lueerror.LueError) {
	var err error
	uRole, errL := srv.getEmpRoleByName(ctx, refId, refType, "客户经理")
	if errL != nil {
		return nil, errL
	}
	if uRole != nil {
		return uRole, nil
	}
	uRole = model.NewEmpRole(brandId, refId, refType, "客户经理", 0)
	uRole.Id, err = dao.GetRoleDao().CreateEmpRole(ctx, uRole)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	var routers []string
	if refType == model.RefTypeBrand {
		routers = []string{"member", "statistic"}
	} else if refType == model.RefTypeStore {
		routers = []string{"member", "statistic"}
	}
	errL = srv.addOrUpdateRolePermissions(ctx, uRole.Id, 0, refType, routers...)
	if errL != nil {
		return nil, errL
	}
	return uRole, nil
}

// 营销经理
func (srv *rolePerService) addMarketingManager(ctx context.Context, brandId, refId int64, refType int8) (*model.EmpRole, lueerror.LueError) {
	var err error
	role, errL := srv.getEmpRoleByName(ctx, refId, refType, "营销经理")
	if errL != nil {
		return nil, errL
	}
	if role != nil {
		return role, nil
	}
	role = model.NewEmpRole(brandId, refId, refType, "营销经理", 0)
	role.Id, err = dao.GetRoleDao().CreateEmpRole(ctx, role)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	// 权限设置
	var routers []string
	if refType == model.RefTypeBrand {
		routers = []string{"member", "statistic", "marketing"}
	} else if refType == model.RefTypeStore {
		routers = []string{"member", "statistic", "marketing"}
	}
	errL = srv.addOrUpdateRolePermissions(ctx, role.Id, 0, refType, routers...)
	if errL != nil {
		return nil, errL
	}
	return role, nil
}

// 商城经理
func (srv *rolePerService) addMallManager(ctx context.Context, brandId, refId int64, refType int8) (*model.EmpRole, lueerror.LueError) {
	var err error
	role, errL := srv.getEmpRoleByName(ctx, refId, refType, "商城经理")
	if errL != nil {
		return nil, errL
	}
	if role != nil {
		return role, nil
	}
	role = model.NewEmpRole(brandId, refId, refType, "商城经理", 0)
	role.Id, err = dao.GetRoleDao().CreateEmpRole(ctx, role)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	// 权限设置
	var routers []string
	if refType == model.RefTypeBrand {
		routers = []string{"product", "statistic", "mall"}
	} else if refType == model.RefTypeStore {
		routers = []string{"product", "statistic", "mall"}
	}
	errL = srv.addOrUpdateRolePermissions(ctx, role.Id, 0, refType, routers...)
	if errL != nil {
		return nil, errL
	}
	return role, nil
}

// CreateDefaultRoles 创建默认角色
func (srv *rolePerService) CreateDefaultRoles(ctx context.Context, brandId, storeId int64) lueerror.LueError {
	if brandId == 0 {
		return nil
	}

	refId, refType := model.GetRefInfoForBrandStore(brandId, storeId)
	_, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		// 创建管理员
		_, errL := srv.addAdminRole(ctx, brandId, refId, refType)
		if errL != nil {
			return nil, errL
		}
		// 客户经理
		_, errL = srv.addMemberManager(ctx, brandId, refId, refType)
		if errL != nil {
			return nil, errL
		}
		// 营销经理
		_, errL = srv.addMarketingManager(ctx, brandId, refId, refType)
		if errL != nil {
			return nil, errL
		}
		// 商城经理
		_, errL = srv.addMallManager(ctx, brandId, refId, refType)
		return nil, errL
	})
	if err != nil {
		return parseLueerror(err)
	}
	return nil
}

// 判断是否是超级管理员
func (srv *rolePerService) isSuperEmp(ctx context.Context, refId, empId int64, refType int8) (bool, lueerror.LueError) {
	// 判断下是否是超级管理员
	if refType == model.RefTypeBrand {
		brand, err := dao.GetBrandDao().GetBrandById(ctx, refId)
		if err != nil {
			return false, lueerror.DbErr(err)
		}
		return brand.SuEmpId == empId, nil
	} else if refType == model.RefTypeStore {
		store, err := dao.GetStoreDao().GetStoreById(ctx, refId)
		if err != nil {
			return false, lueerror.DbErr(err)
		}
		return store.SupEmpId == empId, nil
	}
	return false, nil
}

func (srv *rolePerService) isAdmin(ctx context.Context, refId, empId int64, refType int8) (bool, lueerror.LueError) {
	op, errL := srv.getOperation(ctx, refId, empId, refType)
	if errL != nil {
		return false, errL
	}
	// 检查是否是超级管理员
	if op == nil {
		return srv.isSuperEmp(ctx, refId, empId, refType)
	}
	// 检查权限是否有效
	if !op.IsValid() {
		return false, nil
	}
	// 角色权限检查
	empRole, err := dao.GetRoleDao().GetEmpRoleByIdAndRef(ctx, op.RoleId, refId, refType)
	if err != nil {
		return false, lueerror.DbErr(err)
	}

	return empRole.IsAdmin, nil
}

func (srv *rolePerService) getOperation(ctx context.Context, refId, empId int64, refType int8) (*model.Operator, lueerror.LueError) {
	op, err := dao.GetOperatorDao().GetOperator(ctx, empId, refId, refType)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return op, nil
}

func (srv *rolePerService) normalPermission(ctx context.Context, refId, empId int64, refType int8, router string) (bool, lueerror.LueError) {
	// 获取运营角色
	op, errL := srv.getOperation(ctx, refId, empId, refType)
	if errL != nil {
		return false, errL
	}
	// 是否是超级管理员
	if op == nil {
		return srv.isSuperEmp(ctx, refId, empId, refType)
	}
	if !op.IsValid() {
		return false, nil
	}
	// 根据路由获取权限id
	if router != "" {
		perId := srv.getPermIdByRouter(refType, router)
		// 根据角色id 和 权限id 查询该角色是否拥有对应权限
		rolePerm, err := dao.GetRoleDao().GetRolePermission(ctx, op.RoleId, perId)
		if err != nil {
			return false, lueerror.DbErr(err)
		}
		// rolePerm 不为空，就说明有该权限
		if rolePerm != nil {
			// 第一期，不需要校验二级权限
			return true, nil
		}
	}
	// 判断是否是 管理员角色
	empRole, err := dao.GetRoleDao().GetEmpRoleByIdAndRef(ctx, op.RoleId, refId, refType)
	if err != nil {
		return false, lueerror.DbErr(err)
	}
	return empRole.IsAdmin, nil
}

// PermissionVerify 权限校验
func (srv *rolePerService) PermissionVerify(ctx context.Context, brandId, storeId, empId int64, router string) (bool, lueerror.LueError) {
	refId, refType := model.GetRefInfoForBrandStore(brandId, storeId)
	switch router {
	case "super_admin":
		return srv.isSuperEmp(ctx, refId, empId, refType)
	case "admin":
		return srv.isAdmin(ctx, refId, empId, refType)
	default:
		return srv.normalPermission(ctx, refId, empId, refType, router)
	}
}

// InventoryPermissionVerify 仓库权限校验
func (srv *rolePerService) InventoryPermissionVerify(ctx context.Context, invId, empId int64) (bool, lueerror.LueError) {
	// 先查询员工是否由仓库运营权限
	op, errL := srv.getOperation(ctx, invId, empId, model.RefTypeInventory)
	if errL != nil {
		return false, errL
	}
	// 运营角色存在且有效，则有权限
	if op != nil && op.IsValid() {
		return true, nil
	}
	// 仓库不区分角色
	inv, err := dao.GetInventoryDao().GetInventoryById(ctx, invId)
	if err != nil {
		return false, lueerror.DbErr(err)
	}
	if inv == nil {
		return false, lueerror.InvalidRequest(fmt.Errorf("仓库：%d 不存在", invId))
	}
	refId, refType := model.GetRefInfoForBrandStore(inv.BrandId, inv.StoreId)
	// 是否是超级管理员
	isSuper, errL := srv.isSuperEmp(ctx, refId, empId, refType)
	if errL != nil {
		return false, errL
	}
	if isSuper {
		return true, nil
	}
	// 是否是管理员
	isAdmin, errL := srv.isAdmin(ctx, refId, empId, refType)
	if errL != nil {
		return false, errL
	}
	return isAdmin, nil
}

func (srv *rolePerService) empRoleInfoRelyFormat(role *model.RoleAgg) *pb.EmployeeRoleReply {
	ret := &pb.EmployeeRoleReply{
		RoleId:   role.Role.Id,
		RoleName: role.Role.Name,
		IsAdmin:  role.Role.IsAdmin,
	}
	perms := make([]*pb.RolePermission, len(role.Perms))
	for idx, p := range role.Perms {
		perm := srv.getPermissionById(p.PerId)
		perms[idx] = &pb.RolePermission{
			PerId:   perm.Id,
			PerName: perm.Name,
			Router:  perm.Router,
		}
	}
	ret.RolePermissions = perms
	return ret
}

// GetEmpRoleList 员工角色列表
func (srv *rolePerService) GetEmpRoleList(ctx context.Context, brandId, storeId int64) (*pb.EmployeeRolesReply, lueerror.LueError) {
	refId, refType := model.GetRefInfoForBrandStore(brandId, storeId)
	empRoles, err := dao.GetRoleDao().GetRolesAggByRef(ctx, refId, refType)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	replyRoles := make([]*pb.EmployeeRoleReply, len(empRoles))
	for idx, r := range empRoles {
		replyRoles[idx] = srv.empRoleInfoRelyFormat(r)
	}
	return &pb.EmployeeRolesReply{
		Roles: replyRoles,
	}, nil
}

// CreateEmpRole 创建员工角色
func (srv *rolePerService) CreateEmpRole(ctx context.Context, brandId int64, p *pb.EmployeeRoleCreateReq, creator int64) (*pb.EmployeeRoleReply, lueerror.LueError) {
	if p == nil {
		return nil, nil
	}
	ret, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		var err error
		// 创建角色
		refId, refType := model.GetRefInfoForBrandStore(brandId, p.StoreId)
		uRole := model.NewEmpRole(brandId, refId, refType, p.RoleName, creator)
		uRole.Id, err = dao.GetRoleDao().CreateEmpRole(ctx, uRole)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		// 给角色添加权限
		errL := srv.addOrUpdateRolePermissions(ctx, uRole.Id, creator, refType, p.Routers...)
		if errL != nil {
			return nil, errL
		}
		roleAgg, err := dao.GetRoleDao().GetRoleById(ctx, uRole.Id)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		return roleAgg, nil
	})
	if err != nil {
		return nil, parseLueerror(err)
	}
	return srv.empRoleInfoRelyFormat(ret.(*model.RoleAgg)), nil
}

// UpdateEmpRole 更新权限
func (srv *rolePerService) UpdateEmpRole(ctx context.Context, brandId int64, p *pb.EmployeeRoleUpdateReq, creator int64) (*pb.EmployeeRoleReply, lueerror.LueError) {
	if p == nil {
		return nil, nil
	}
	empRole, err := dao.GetRoleDao().GetEmpRoleById(ctx, p.RoleId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if empRole == nil {
		return nil, lueerror.InvalidRole(fmt.Errorf("角色: %d 不存在", p.RoleId))
	}
	if empRole.BrandId != brandId {
		return nil, lueerror.InvalidRole(fmt.Errorf("角色品牌不一致"))
	}
	ret, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		empRole.Update(p.RoleName, creator)
		err = dao.GetRoleDao().UpdateEmpRole(ctx, empRole)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		errL := srv.addOrUpdateRolePermissions(ctx, empRole.Id, creator, empRole.RefType, p.Routers...)
		if errL != nil {
			return nil, errL
		}
		roleAgg, err := dao.GetRoleDao().GetRoleById(ctx, empRole.Id)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		return roleAgg, nil
	})
	if err != nil {
		return nil, parseLueerror(err)
	}
	return srv.empRoleInfoRelyFormat(ret.(*model.RoleAgg)), nil
}

// SendMsgById 发送消息（暂时存放)
func (srv *rolePerService) SendMsgById(ctx context.Context, id int64) lueerror.LueError {
	err := dao.GetMessageDao().ReSendMessageById(ctx, id)
	if err != nil {
		return lueerror.MqErr(err)
	}
	return nil
}

// GetPermissions 获取权限列表
func (srv *rolePerService) GetPermissions(_ context.Context, storeId int64) (*pb.PermissionListReply, lueerror.LueError) {
	perms := srv.loadPermsMap().BrandPerms
	if storeId != 0 {
		perms = srv.loadPermsMap().StorePerms
	}

	rPerms := make([]*pb.RolePermission, len(perms))
	for idx, p := range perms {
		rPerms[idx] = &pb.RolePermission{
			PerId:   p.Id,
			PerName: p.Name,
			Router:  p.Router,
		}
	}
	return &pb.PermissionListReply{Permissions: rPerms}, nil
}

// GetRoleInfoById 获取角色详情
func (srv *rolePerService) GetRoleInfoById(ctx context.Context, brandId, roleId, storeId int64) (*pb.EmployeeRoleReply, lueerror.LueError) {
	roleAgg, err := dao.GetRoleDao().GetRoleById(ctx, roleId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if roleAgg == nil || roleAgg.Role.BrandId != brandId {
		return nil, lueerror.InvalidRole(fmt.Errorf("角色: %d 无效", roleId))
	}
	// 不能捞过界
	refId, refType := model.GetRefInfoForBrandStore(brandId, storeId)
	if roleAgg.Role.RefId != refId || roleAgg.Role.RefType != refType {
		return nil, lueerror.InvalidRole(fmt.Errorf("角色: %d 无效", roleId))
	}
	ret := &pb.EmployeeRoleReply{
		RoleId:   roleAgg.Role.Id,
		RoleName: roleAgg.Role.Name,
		IsAdmin:  roleAgg.Role.IsAdmin,
	}
	perms := make([]*pb.RolePermission, len(roleAgg.Perms))
	for idx, p := range roleAgg.Perms {
		perm := srv.getPermissionById(p.PerId)
		perms[idx] = &pb.RolePermission{
			PerId:   perm.Id,
			PerName: perm.Name,
			Router:  perm.Router,
		}
	}
	ret.RolePermissions = perms
	return ret, nil
}
